﻿/*
 * QtPet Online File Manager v1.0
 * Copyright (c) 2009, Zhifeng Lin (fszlin[at]gmail.com)
 * 
 * Licensed under the MS-PL license.
 * http://qtfile.codeplex.com/license
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace QtFile.FileBased
{
	/// <summary>
	/// Represents the root folder of a user.
	/// </summary>
	public class RootFolder
	{
		private long size = -1;

		private int folderCount = -1;

		private int fileCount = -1;

		private readonly char dirSeparator;

		/// <summary>
		/// Creates a new instance for specified user.
		/// </summary>
		/// <param name="rootPath">
		/// The root path of file service.
		/// </param>
		/// <param name="username">
		/// The name of user.
		/// </param>
		/// <param name="encodeUsername">
		/// Whether encode the username, should be true is username may contain special characters.
		/// </param>
		/// <param name="dirSeparator">
		/// The path separator.
		/// </param>
		public RootFolder(string rootPath, string username, bool encodeUsername, char dirSeparator)
		{
			Helper.ValidateNotNullOrEmpty(rootPath, "rootPath");
			Helper.ValidateNotNullOrEmpty(username, "username");

			if (encodeUsername)
				username = Encode(username);

			RootPath = Path.Combine(rootPath, username);

			if (!Directory.Exists(RootPath))
				Directory.CreateDirectory(RootPath);

			this.dirSeparator = dirSeparator;
		}

		/// <summary>
		/// Gets the root path of current user.
		/// </summary>
		/// <value>
		/// The root path of current user.
		/// </value>
		public string RootPath
		{
			get;
			private set;
		}

		public int CountFiles()
		{
			if (fileCount < 0)
				UpdateInfo();
			return fileCount;
		}

		public int CountFolders()
		{
			if (folderCount < 0)
				UpdateInfo();
			return folderCount;
		}

		public long GetSize()
		{
			if (size < 0)
				UpdateInfo();
			return size;
		}

		public string GetPath(params string[] segments)
		{
			var path = RootPath;
			foreach (var segment in segments)
				path = Path.Combine(path, segment.Replace(dirSeparator, Path.DirectorySeparatorChar));
			return path;
		}

		private void UpdateInfo()
		{
			size = 0;
			fileCount = 0;
			folderCount = 0;
			UpdateInfo(RootPath);
		}

		private void UpdateInfo(string path)
		{
			var files = Directory.GetFiles(path);
			fileCount += files.Length;
			foreach (var filePath in files)
			{
				size += new FileInfo(filePath).Length;
			}
			var subfolders = Directory.GetDirectories(path);
			folderCount += subfolders.Length;
			foreach (var folderPath in subfolders)
			{
				UpdateInfo(folderPath);
			}
		}

		private static string Encode(string username)
		{
			var binaryData = Encoding.Unicode.GetBytes(username);

			long arrayLength = (long)((4.0d / 3.0d) * binaryData.Length);
			if (arrayLength % 4 != 0)
				arrayLength += 4 - arrayLength % 4;

			char[] base64CharArray = new char[arrayLength];

			Convert.ToBase64CharArray(binaryData, 0, binaryData.Length, base64CharArray, 0);

			for (int i = 0; i < base64CharArray.Length; ++i)
				if (base64CharArray[i] == '+')
					base64CharArray[i] = '-';
				else if (base64CharArray[i] == '/')
					base64CharArray[i] = '_';

			return new String(base64CharArray);
		}
	}
}
